package com.dance.java8.day01;

import com.dance.java8.entity.Person;
import org.junit.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;

public class TestStreamApi {

    @Test
    public void createStream() {
        // 1:通过Collection系列集合提供的stream() 或 parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
        Stream<String> stringStream = list.parallelStream();

        // 2:通过Arrays中的静态方法Stream()获取数组流
        String[] strings = new String[10];
        Stream<String> stream1 = Arrays.stream(strings);

        // 3:通过Stream类中的静态方法of()
        Stream<String> stringStream1 = Stream.of("1", "2", "3");

        // 4:创建无限流
        // 迭代
        Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
        // 产生10个数值
        iterate.limit(10).forEach(System.out::println);

        // 生成
        Stream<Double> generate = Stream.generate(Math::random);
        generate.forEach(System.out::println);
    }

    /**
     * 筛选与切片
     * filter - 接收Lambda,从流中排除某些元素
     * limit - 截断流,使其元素不超过给定数量
     * skip(n) - 跳过元素,返回一个扔掉前N个元素的流,若流中元素不足N个,则返回一个空流,与limit(n)互补
     * distinct - 筛选,通过流所产生元素的hashcode()和equals()去除重复元素
     */

    List<Person> personList = Arrays.asList(
            new Person("张三", 18),
            new Person("张三", 18),
            new Person("张三", 18),
            new Person("李四", 22),
            new Person("王五", 27),
            new Person("赵六", 31),
            new Person("天启", 50)
    );

    @Test
    public void test2() {
        // 过滤年龄大于30的人员
        personList.stream().filter(x -> x.getAge() > 30).forEach(System.out::println);
    }

    @Test
    public void test3() {
        // 获取两个人员
        personList.stream().limit(2).forEach(System.out::println);
    }

    @Test
    public void test4() {
        // 获取年龄大于18的后两位
        personList.stream().filter(x -> x.getAge() > 18).skip(2).forEach(System.out::println);
    }

    @Test
    public void test5() {
        // 去重 // 如果没有去除重复的,可以重写Equals和HashCode
        personList.stream().distinct().forEach(System.out::println);
    }

    /**
     * 映射
     * map - 接收 Lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
     * flatmap - 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流链接成一个流
     */
    @Test
    public void test6() {
        List<String> list = Arrays.asList("a", "b", "c", "d");
        // 全部转大写
        list.stream().map(String::toUpperCase).forEach(System.out::println);
    }

    @Test
    public void test7() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
//        Stream<Stream<Character>> streamStream = list.stream().map(TestStreamApi::stringToCharacter);
        // 应为返回的是流,所以会造成嵌套流结构
//        streamStream.forEach(s -> {
//            s.forEach(System.out::println);
//        });
        // 这个时候就可以使用flatmap,将所有的流整合成一个流
        list.stream().flatMap(TestStreamApi::stringToCharacter).forEach(System.out::println);
    }

    /**
     * 返回流
     *
     * @param str 字符串
     * @return
     */
    public static Stream<Character> stringToCharacter(String str) {
        List<Character> characters = new ArrayList<>();
        for (Character character : str.toCharArray()) {
            characters.add(character);
        }
        return characters.stream();
    }

    /**
     * 排序
     * sorted() - 自然排序
     * sorted(Comparator c) - 定制排序
     */

    @Test
    public void test8() {
        List<String> list = Arrays.asList("c", "f", "a", "d", "b");
        // 自然排序
        list.stream().sorted().forEach(System.out::println);
    }

    @Test
    public void test9() {
        personList.stream().sorted(((o1, o2) -> {
            if (o1.getAge().equals(o2.getAge())) {
                return o1.getName().compareTo(o2.getName());
            }
            return o1.getAge().compareTo(o2.getAge());
        })).forEach(System.out::println);
    }

    /**
     * 查找与匹配
     * allMatch - 检查是否匹配所有元素
     * anyMatch - 检查是否至少匹配一个元素
     * noneMatch - 检查是否没有匹配所有元素
     * findFirst - 返回第一个元素
     * findAny - 返回当前流中的任意元素
     * count - 返回流中元素的总个数
     * max - 返回流中的最大值
     * min - 返回流中的最小值
     */
    @Test
    public void test10() {
        // 是否全部为18岁
        boolean b = personList.stream().allMatch(e -> e.getAge().equals(18));
        System.out.println("is all match: " + b);
        // 是否有人为18岁
        boolean b1 = personList.stream().anyMatch(e -> e.getAge().equals(18));
        System.out.println("is any match: " + b1);
        // 是否没有人为18岁
        boolean b2 = personList.stream().noneMatch(e -> e.getAge().equals(18));
        System.out.println("is none match: " + b2);
        // 获取年龄最小的人
        Optional<Person> first = personList.stream().sorted(Comparator.comparingInt(Person::getAge)).findFirst();
        System.out.println("first age is: " + first.get());
        // 从年龄为18岁的人群中随便找一个人
        Optional<Person> any = personList.stream().filter(s -> s.getAge().equals(18)).findAny();
        System.out.println("age 18 is: " + any.get());
        // 获取总数
        long count = personList.stream().count();
        System.out.println("count num is:" + count);
        // 获取年龄最大的人
        Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getAge));
        System.out.println("age max is: " + max);
        // 获取年龄最小的人
        Optional<Person> min = personList.stream().min(Comparator.comparingInt(Person::getAge));
        System.out.println("age min is:" + min);

    }
    /**
     * 归约
     * reduce(T identity,BinaryOperator) / reduce(BinaryOperator) - 可以从流中元素反复结合起来,得到一个值
     */
    @Test
    public void test11(){
        // 计算数组总和
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer reduce = integers.stream().reduce(0, Integer::sum);
        System.out.println(reduce);
        // 计算人员年龄总和
        Optional<Integer> reduce1 = personList.stream().map(Person::getAge).reduce(Integer::sum);
        System.out.println("person age count is : "+reduce1.get());
    }

    /**
     * 收集
     * collect - 将流转化为其他形式,接收一个Collector接口的实现,用于Stream中元素做汇总的方法
     */
    @Test
    public void test12(){

        // 收集所有人员的名字并转换为List<String>
        List<String> collect = personList.stream().map(Person::getName).collect(Collectors.toList());
        System.out.println(" name list is : "+collect);
        // 收集所有人员的名字并转换为Set<String>
        Set<String> collect1 = personList.stream().map(Person::getName).collect(Collectors.toSet());
        // 收集所有人员的名字并转换为HashSet<String>
        HashSet<String> collect2 = personList.stream().map(Person::getName).collect(Collectors.toCollection(HashSet::new));

        // 获取总数
        Long collect3 = personList.stream().collect(Collectors.counting());
        System.out.println("counting is : "+collect3);

        // 获取人员年龄平均自
        Double collect4 = personList.stream().collect(Collectors.averagingInt(Person::getAge));
        System.out.println("avg is :" + collect4);

        // 获取所有人员的年龄总和
        Integer collect5 = personList.stream().collect(Collectors.summingInt(Person::getAge));
        System.out.println("sum is : " + collect5);

        // 获取年龄最大的
        Optional<Person> collect6 = personList.stream().collect(Collectors.maxBy((x, y) -> Integer.compare(x.getAge(), y.getAge())));
        System.out.println("max by is : "+collect6);

        // 获取年龄最小值
        Optional<Integer> collect7 = personList.stream().map(Person::getAge).collect(Collectors.minBy(Integer::compare));
        System.out.println("age min is:" + collect7);

        // 按照年龄分组
        Map<Integer, List<Person>> collect8 = personList.stream().collect(Collectors.groupingBy(Person::getAge));
        System.out.println("grouping by is:"+collect8);

        // 多级分组
        Map<String, Map<String, List<Person>>> collect9 = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getName)));
        System.out.println("多级分组:"+collect9);

        // 条件分区
        Map<Boolean, List<Person>> collect10 = personList.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 25));
        System.out.println("partitioningBy is:"+collect10);

        // 多级分区
        Map<Boolean, Map<Boolean, List<Person>>> collect11 = personList.stream().collect(Collectors.partitioningBy(x -> x.getAge() > 25, Collectors.partitioningBy(y -> y.getName().equals("张三"))));
        System.out.println("多级分区:"+collect11);

        // 获取数值计算容器类
        IntSummaryStatistics collect12 = personList.stream().collect(Collectors.summarizingInt(Person::getAge));
        System.out.println(collect12.getMax());
        System.out.println(collect12.getSum());
        System.out.println(collect12.getAverage());
        System.out.println(collect12.getMin());
        System.out.println(collect12.getCount());

        // 通过中划线链接所有人的名称
        String collect13 = personList.stream().map(Person::getName).collect(Collectors.joining("-"));
        System.out.println("names is :" + collect13);
    }

    @Test
    public void test13(){
        Instant now = Instant.now();
        long reduce = LongStream.rangeClosed(0, 100000000000L)
                .reduce(0, Long::sum);
        System.out.println(reduce);
        Instant end = Instant.now();
        System.out.println("耗时:"+Duration.between(now,end).toMillis());
    }
    @Test
    public void test14(){
        Instant now = Instant.now();
        long reduce = LongStream.rangeClosed(0, 100000000000L)
                .reduce(0, Long::sum);
        System.out.println(reduce);
        Instant end = Instant.now();
        System.out.println("耗时:"+Duration.between(now,end).toMillis());
    }
}
